package com.sinodata.bsm.center.engine.notify;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.sinodata.bsm.center.bean.NotifyRuleBean;
import com.sinodata.bsm.center.service.notify.NotifyService;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.EventConstants;
import com.sinodata.bsm.common.vo.Event;
import com.sinodata.bsm.common.vo.Notify;
import com.sinodata.bsm.common.vo.NotifyReceiveRule;

/**
 * 
 * <p>
 * Description:事件通知引擎 
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-29 PM 1:45:45     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class NotifyEngine {

    private static final Logger logger = Logger.getLogger("notify");

    private static NotifyMessenger messenger = null;

    private static NotifyService notifyService = SpringContextHolder.getBean(NotifyService.class);

    /**
     * 启动事件通知服务
     */
    public static void start() {
        messenger = new NotifyMessenger();
        messenger.start();
        logger.info("[TIP]>>>>>Start Notify Enginer");
    }

    /**
     * 对一个事件进行通知
     * 
     * @param eventValue
     */
    public static void notify(Event event) {
        Long resId = event.getResId();
        Long eventTypeId = event.getEventTypeId();
        Long eventId = event.getId();
        Integer level = event.getLevel();
        Integer faultType = event.getCatalog();
        List<Notify> notifys = new ArrayList<Notify>();
        List<NotifyRuleBean> rules = NotifyRuleBean.getAvailableNotifyRules(resId, eventTypeId, level);
        //去掉通知类型、  提升类别、 恢复类别 ，通过 持续时间、 事件类别 判断
        for (int i = 0; i < rules.size(); i++) {
            NotifyRuleBean rule = rules.get(i);
            // int type = rule.notifyRule().getType();
            String levels = rule.notifyRule().getEventLevels();
            Long duration = rule.notifyRule().getDuration();
            if (duration == 0 && faultType == EventConstants.CATALOG_FAULTEVENT) {
                notifys.addAll(createTimelyNotifys(rule, event));
            } else if (duration > 0 && faultType == EventConstants.CATALOG_FAULTEVENT) {
                notifys.addAll(createUpgradeNotifys(rule, event));
            } else if (levels.contains(EventConstants.LEVEL_NORMAL + "") && faultType == EventConstants.CATALOG_REFAULTEVENT) {
                notifys.addAll(createResumeNotifys(rule, event));
            }
        }
        //去重
        for (int i = notifys.size() - 1; i > 0; i--) {
            Notify v = notifys.get(i);
            for (int j = 0; j < i; j++) {
                Notify v2 = notifys.get(j);
                if (v2.getUser().equals(v.getUser()) && v2.getNotifyMode().intValue() == v.getNotifyMode().intValue() && v2.getTime().equals(v.getTime())) {
                    notifys.remove(i);
                    break;
                }
            }
        }
        for (int i = 0; i < notifys.size(); i++) {
            Notify notify = notifys.get(i);
            notify.setEventId(eventId);
            logger.info("[SEND]\t" + notify.toString());
        }
        try {
            notifyService.batchAdd(notifys);
            logger.info("[TIP]\t CNT=" + notifys.size());
        } catch (Exception e) {
        }
        messenger.interrupt();
    }

    /**
     * 构建及时通知
     * 
     * @param rule
     * @param eventValue
     * @return
     */
    private static List<Notify> createTimelyNotifys(NotifyRuleBean rule, Event event) {
        List<Notify> notifys = new ArrayList<Notify>();
        List<NotifyReceiveRule> receivers = rule.getNotifyReceiveRules();
        if (receivers != null) {
            for (int i = 0; i < receivers.size(); i++) {
                NotifyReceiveRule rr = receivers.get(i);
                NotifyMode alarmMode = NotifyModeFactory.getInstance().getNotifyMode(rr.getNotifyMode());
                if (alarmMode == null) {
                    logger.info("The system does not support the alarm mode:" + rr.getNotifyMode());
                    continue;
                }
                long begin = System.currentTimeMillis();
                for (int j = 0; j < rr.getTimes(); j++) {
                    Notify notify = new Notify();
                    notify.setUser(rr.getUser());
                    notify.setNotifyMode(rr.getNotifyMode());
                    long time = j == 0 ? begin : begin + rr.getInterval() * 1000L;
                    begin = rule.getNextValidNotifyTime(time);
                    notify.setTime(new Date(begin));
                    notify.setMsg(alarmMode.createNotifyMessage(event));
                    notify.setMsgExpr(event.getMsgExpr());
                    notify.setNotifyRuleId(rule.notifyRule().getId());
                    notifys.add(notify);
                }
            }
        }
        return notifys;
    }

    /**
     * 构建提升通知
     * 
     * @param rule
     * @param eventValue
     * @return
     */
    private static List<Notify> createUpgradeNotifys(NotifyRuleBean rule, Event event) {
        List<Notify> notifys = new ArrayList<Notify>();
        List<NotifyReceiveRule> receivers = rule.getNotifyReceiveRules();
        if (receivers != null) {
            for (int i = 0; i < receivers.size(); i++) {
                NotifyReceiveRule rr = receivers.get(i);
                NotifyMode alarmMode = NotifyModeFactory.getInstance().getNotifyMode(rr.getNotifyMode());
                if (alarmMode == null) {
                    logger.info("The system does not support the alarm mode:" + rr.getNotifyMode());
                    continue;
                }
                long begin = System.currentTimeMillis();
                begin = rule.getNextValidNotifyTime(begin) + Integer.parseInt(rule.notifyRule().getDuration().toString()) * 1000L;
                for (int j = 0; j < rr.getTimes(); j++) {
                    Notify Notify = new Notify();
                    Notify.setUser(rr.getUser());
                    Notify.setNotifyMode(rr.getNotifyMode());
                    long time = j == 0 ? begin : begin + rr.getInterval() * 1000L;
                    begin = rule.getNextValidNotifyTime(time);
                    Notify.setTime(new Date(begin));
                    Notify.setMsg(alarmMode.createNotifyMessage(event));
                    Notify.setMsgExpr(event.getMsgExpr());
                    Notify.setNotifyRuleId(rule.notifyRule().getId());
                    notifys.add(Notify);
                }
            }
        }
        return notifys;
    }

    /**
     * 构建恢复通知、恢复通知只发一次
     * 
     * @param rule
     * @param eventValue
     * @return
     */
    private static List<Notify> createResumeNotifys(NotifyRuleBean rule, Event event) {
        List<Notify> notifys = new ArrayList<Notify>();
        List<NotifyReceiveRule> receivers = rule.getNotifyReceiveRules();
        if (receivers != null) {
            for (int i = 0; i < receivers.size(); i++) {
                NotifyReceiveRule rr = receivers.get(i);
                String userAccount = null;
                userAccount = rr.getUser();
                NotifyMode alarmMode = NotifyModeFactory.getInstance().getNotifyMode(rr.getNotifyMode());
                if (alarmMode == null) {
                    logger.info("The system does not support the notify mode:" + rr.getNotifyMode());
                    continue;
                }
                long begin = System.currentTimeMillis();
                Notify notify = new Notify();
                notify.setUser(userAccount);
                notify.setNotifyMode(rr.getNotifyMode());
                notify.setTime(new Date(begin));
                notify.setMsg(alarmMode.createResumeMessage(event));
                notify.setNotifyRuleId(rule.notifyRule().getId());
                notifys.add(notify);
            }
        }
        return notifys;
    }

}